#include "Shader.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include "core.h"
Shader::Shader(const char *vertexPath, const char *fragmentPath)
{
	GLuint  vertexShader=compile(vertexPath,GL_VERTEX_SHADER);
	GLuint  fragmentShader= compile(fragmentPath,GL_FRAGMENT_SHADER);
	m_id= link(vertexShader,fragmentShader);
}

Shader::~Shader()
{
	glDeleteProgram(m_id);
}

GLuint Shader::compile(const char* path,GLuint type)
{

	std:: ifstream infile;
	std::string source;
	infile.exceptions(std::ifstream::failbit|std::ifstream::badbit);
	try
	{
		infile.open(path);
		std::stringstream sstream;
		sstream<<infile.rdbuf();
		infile.close();
		source=sstream.str();
	}catch(std::ifstream::failure e)
	{
		ASSERT(0,"shader read fail");
	}
	GLuint id=glCreateShader(type);
	const char* src=source.c_str();
	glShaderSource(id,1,&src, nullptr);
	glCompileShader(id);
	int ok;
	char infoLogBuf[512];
	glGetShaderiv(id,GL_COMPILE_STATUS,&ok);
	if(!ok)
	{
		glGetShaderInfoLog(id, 512, nullptr,infoLogBuf);
		glDeleteShader(id);
		ASSERT_INFO(0,"shader compile fail",infoLogBuf);
	}
	return id;
}

GLuint Shader::link(GLuint &vertexShader,GLuint &fragmentShader)
{
	GLuint  id=glCreateProgram();
	glAttachShader(id,vertexShader);
	glAttachShader(id,fragmentShader);
	glLinkProgram(id);
	char infoLogBuf[512];
	int ok;
	glGetProgramiv(id,GL_LINK_STATUS,&ok);
	if(!ok)
	{
		glGetProgramInfoLog(id,512, nullptr,infoLogBuf);
		glDeleteProgram(id);
		glGetShaderInfoLog(id, 512, nullptr,infoLogBuf);
		glDeleteShader(id);
		ASSERT_INFO(0,"shader link fail",infoLogBuf);
	}
	glDeleteShader(fragmentShader);
	glDeleteShader(vertexShader);
	fragmentShader=0;
	vertexShader=0;
	return id;
}

void Shader::use() const
{
	glUseProgram(m_id);
}

GLuint Shader::getProgram() const
{
	return m_id;
}

void Shader::setVec4(const char *name, double x, double y, double z, double w)const
{
	glUniform4f(glGetUniformLocation(m_id,name),x,y,z,w);
}

void Shader::setInt(const char *name, int value)const
{
	glUniform1i(glGetUniformLocation(m_id,name),value);
}


void Shader::setFloat(const char* name, float value) const
{
	glUniform1f(glGetUniformLocation(m_id,name), value);
}

void Shader::setMat4(const char *name, const glm::mat4 &mat) const
{
	glUniformMatrix4fv(glGetUniformLocation(m_id,name),1, GL_FALSE, glm::value_ptr(mat));
}

void Shader::setVec3(const std::string &name, const glm::vec3 &value) const
{
    glUniform3fv(glGetUniformLocation(m_id, name.c_str()), 1, &value[0]);
}

